package io.github.wycst.wast.common.utils;

import io.github.wycst.wast.common.compiler.MemoryClassLoader;
import io.github.wycst.wast.common.reflect.UnsafeHelper;

import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.util.List;

public final class EnvUtils {

    public static final float JDK_VERSION;

    public static final boolean JDK_7_BELOW;
    public static final boolean JDK_8_PLUS;
    public static final boolean JDK_16_PLUS;
    public static final boolean JDK_9_PLUS;
    public static final boolean JDK_20_PLUS;

    public static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
    public static final boolean LITTLE_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN;
    public static final int HI_BYTE_SHIFT;
    public static final int LO_BYTE_SHIFT;
    public static final boolean SUPPORTED_VECTOR;

    // 'java.lang.String' hashcode
    public final static int STRING_HV = 1195259493;
    // 'int' hash
    public final static int INT_HV = 104431;
    // 'java.lang.Integer' hash
    public final static int INTEGER_HV = -2056817302;
    // 'long'
    public final static int LONG_PRI_HV = 3327612;
    // 'java.lang.Long'
    public final static int LONG_HV = 398795216;
    // 'java.util.HashMap'
    public final static int HASHMAP_HV = -1402722386;
    // 'java.util.LinkHashMap'
    public final static int LINK_HASHMAP_HV = 1258621781;

    // 'java.util.ArrayList'
    public final static int ARRAY_LIST_HV = -1114099497;
    // 'java.util.HashSet'
    public final static int HASH_SET_HV = -1402716492;

    public final static Charset CHARSET_DEFAULT = Charset.defaultCharset();
    //    public final static Charset CHARSET_ISO_8859_1 = forCharsetName("ISO_8859_1");
    public final static Charset CHARSET_UTF_8 = forCharsetName("UTF-8");
    public final static Charset CHARSET_UTF8_OR_DEF = CHARSET_UTF_8 == null ? CHARSET_DEFAULT : CHARSET_UTF_8;
    public static final Method SC_HAS_NEGATIVES_METHOD;

    static {
        float jdkVersion = 1.8f;
        try {
            // 规范版本号
            String version = System.getProperty("java.specification.version");
            if (version != null) {
                jdkVersion = Float.parseFloat(version);
            }
        } catch (Throwable throwable) {
        }
        JDK_VERSION = jdkVersion;
        JDK_7_BELOW = JDK_VERSION < 1.7f;
        JDK_8_PLUS = JDK_VERSION >= 1.8f;
        JDK_9_PLUS = JDK_VERSION >= 9;
        JDK_16_PLUS = JDK_VERSION >= 16;
        JDK_20_PLUS = JDK_VERSION >= 20;

        if (BIG_ENDIAN) {
            HI_BYTE_SHIFT = 8;
            LO_BYTE_SHIFT = 0;
        } else {
            HI_BYTE_SHIFT = 0;
            LO_BYTE_SHIFT = 8;
        }

        Method scHasNegatives = null;
        if (JDK_9_PLUS) {
            try {
                Class<?> scClass = Class.forName("java.lang.StringCoding");
                scHasNegatives = scClass.getMethod("hasNegatives", new Class[]{byte[].class, int.class, int.class});
                UnsafeHelper.setAccessible(scHasNegatives);
            } catch (Exception e) {
                scHasNegatives = null;
            }
        }
        SC_HAS_NEGATIVES_METHOD = scHasNegatives;

        boolean supportedVector = false;
        if (JDK_VERSION >= 17f) {
            try {
                List<String> inputArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
                supportedVector = inputArguments.contains("--add-modules=jdk.incubator.vector");
            } catch (Throwable throwable) {
            }
        }
        SUPPORTED_VECTOR = supportedVector;
    }

    public static final JdkApiAgent JDK_AGENT_INSTANCE;

    static {
        JdkApiAgent apiAgent = null;
        if (EnvUtils.JDK_9_PLUS) {
            try {
                MemoryClassLoader memoryClassLoader = new MemoryClassLoader();
                Class agentClass = memoryClassLoader.loadClass("io.github.wycst.wast.common.utils.JdkApiAgentJdk9Plus", ByteUtils.hexString2Bytes("CAFEBABE0000003500720A001700410A0042004309001600440A003E00450700460A0017004707004908004A0A0011004B0A004C004D0A004E004F0A004800500800510A001100520A0007005308002707005407002A09005500560A001100570A0007005807005907005A0100144841535F4E45474154495645535F48414E444C4501001F4C6A6176612F6C616E672F696E766F6B652F4D6574686F6448616E646C653B0100063C696E69743E010003282956010004436F646501000F4C696E654E756D6265725461626C650100124C6F63616C5661726961626C655461626C65010004746869730100374C696F2F6769746875622F77796373742F776173742F636F6D6D6F6E2F7574696C732F4A646B4170694167656E744A646B39506C75733B01000C6D756C7469706C7948696768010005284A4A294A010001780100014A010001790100156D756C7469706C79486967684B617261747375626101000C6861734E6567617469766573010007285B424949295A01000562797465730100025B420100066F6666736574010001490100036C656E01000D537461636B4D61705461626C650100083C636C696E69743E0100056669656C640100194C6A6176612F6C616E672F7265666C6563742F4669656C643B0100077363436C6173730100114C6A6176612F6C616E672F436C6173733B01000663616C6C65720100064C6F6F6B757001000C496E6E6572436C61737365730100274C6A6176612F6C616E672F696E766F6B652F4D6574686F6448616E646C6573244C6F6F6B75703B0100126861734E65676174697665734D6574686F6401001A4C6A6176612F6C616E672F7265666C6563742F4D6574686F643B0100066C6F6F6B75700100186861734E65676174697665734D6574686F6448616E646C650100164C6F63616C5661726961626C65547970655461626C650100144C6A6176612F6C616E672F436C6173733C2A3E3B07005B01000A536F7572636546696C650100184A646B4170694167656E744A646B39506C75732E6A6176610C001A001B07005C0C002100220C001800190C005D00280100136A6176612F6C616E672F5468726F7761626C650C0027002807005E0100256A6176612F6C616E672F696E766F6B652F4D6574686F6448616E646C6573244C6F6F6B757001000B494D504C5F4C4F4F4B55500C005F00600700610C006200630700640C006500660C003A00670100166A6176612E6C616E672E537472696E67436F64696E670C006800690C006A006B01000F6A6176612F6C616E672F436C61737307006C0C006D00330C006E006F0C00700071010035696F2F6769746875622F77796373742F776173742F636F6D6D6F6E2F7574696C732F4A646B4170694167656E744A646B39506C757301002D696F2F6769746875622F77796373742F776173742F636F6D6D6F6E2F7574696C732F4A646B4170694167656E7401001D6A6176612F6C616E672F696E766F6B652F4D6574686F6448616E646C6501000E6A6176612F6C616E672F4D617468010006696E766F6B6501001E6A6176612F6C616E672F696E766F6B652F4D6574686F6448616E646C65730100106765744465636C617265644669656C6401002D284C6A6176612F6C616E672F537472696E673B294C6A6176612F6C616E672F7265666C6563742F4669656C643B010030696F2F6769746875622F77796373742F776173742F636F6D6D6F6E2F7265666C6563742F556E7361666548656C70657201000D73657441636365737369626C65010027284C6A6176612F6C616E672F7265666C6563742F41636365737369626C654F626A6563743B295A0100176A6176612F6C616E672F7265666C6563742F4669656C64010003676574010026284C6A6176612F6C616E672F4F626A6563743B294C6A6176612F6C616E672F4F626A6563743B01002928294C6A6176612F6C616E672F696E766F6B652F4D6574686F6448616E646C6573244C6F6F6B75703B010007666F724E616D65010025284C6A6176612F6C616E672F537472696E673B294C6A6176612F6C616E672F436C6173733B010002696E01003A284C6A6176612F6C616E672F436C6173733B294C6A6176612F6C616E672F696E766F6B652F4D6574686F6448616E646C6573244C6F6F6B75703B0100116A6176612F6C616E672F496E7465676572010004545950450100096765744D6574686F64010040284C6A6176612F6C616E672F537472696E673B5B4C6A6176612F6C616E672F436C6173733B294C6A6176612F6C616E672F7265666C6563742F4D6574686F643B010009756E7265666C65637401003B284C6A6176612F6C616E672F7265666C6563742F4D6574686F643B294C6A6176612F6C616E672F696E766F6B652F4D6574686F6448616E646C653B00310016001700000001001800180019000000050001001A001B0001001C0000002F00010001000000052AB70001B100000002001D0000000600010000000E001E0000000C000100000005001F002000000001002100220001001C0000004400040005000000061F21B80002AD00000002001D0000000600010000002A001E00000020000300000006001F0020000000000006002300240001000000060025002400030001002600220001001C0000004400040005000000061F21B80002AD00000002001D0000000600010000002E001E00000020000300000006001F0020000000000006002300240001000000060025002400030001002700280001001C00000083000400050000001AB20003C6000FB200032B1C1DB60004AC3A042A2B1C1DB70006AC00010006000F001000050003001D00000012000400000033000600350010003600120039001E0000002A00040000001A001F002000000000001A0029002A00010000001A002B002C00020000001A002D002C0003002E00000007000250070005010008002F001B0001001C0000014F0006000500000065014B12071208B600094C2BB8000A572B01B6000BC000074BA700044C2AC70007B8000C4B014C120DB8000E4D2A2CB6000F4E2C121006BD001159031212535904B20013535905B2001353B600143A041904B8000A572D1904B600154CA700044D2BB30003B1000200020018001B00050026005C005F00050004001D0000004A00120000001300020015000A0016000F001700180019001B0018001C001A0020001B0024001D0026001F002C002000320021004F002200550023005C0025005F00240060002600640027001E0000003E0006000A000E003000310001002C00300032003300020032002A003400370003004F000D00380039000400020062003A003700000026003E003B00190001003C0000000C0001002C00300032003D0002002E000000220005FF001B000107000700010700050007FF003A000207000707003E0001070005000002003F00000002004000360000000A00010007004800350019"));
                apiAgent = (JdkApiAgent) UnsafeHelper.newInstance(agentClass);
            } catch (Throwable throwable) {
            }
        }
        if (apiAgent == null) {
            apiAgent = new JdkApiAgent();
        }
        JDK_AGENT_INSTANCE = apiAgent;
    }

    private static Charset forCharsetName(String charsetName) {
        try {
            return Charset.forName(charsetName);
        } catch (Throwable throwable) {
            return null;
        }
    }

    public static boolean hasNegatives(byte[] bytes, int offset, int len) {
        return JDK_AGENT_INSTANCE.hasNegatives(bytes, offset, len);
    }

    // only supported on JDK9+
    public static boolean hasNegativesReflect(byte[] bytes, int offset, int len) {
        try {
            return (Boolean) SC_HAS_NEGATIVES_METHOD.invoke(null, bytes, offset, len);
        } catch (Exception e) {
            throw new UnsupportedOperationException();
        }
    }
}
